/**  
 *  GenevaJS, version x
 *  (c) 2009 Rick waldron
 *
 *  MIT license.
 *
 *
 *  THIS VERSION OF GENEVA IS FOR DEVELOPMENT ONLY
 *  DO NOT USE IN PRODUCTION ENVIRONMENTS -- INCOMPLETE TESTING!!
 *--------------------------------------------------------------------------
*/
// NOT PART OF GENEVA CORE -- TEMPORARY
String.prototype.trim = function() {
  return this.replace( /^\s+|\s+$/g, '' );
};
String.prototype.clean = function() {
  return this.replace(/\t/g, '').replace(/\s+/g, ' ');
};
// END -- NOT PART OF GENEVA CORE -- TEMPORARY

//  $ stored as _$, used in the window.$ adapter
(function ( _$ ) {
  
  //  Prototype class/objects to copy
  var _classobjects   = [ Element.Methods, Form.Methods, Form.Element.Methods ]; //?    

  //  Geneva class object with Enumerable mixin 
  //  (previous builds attempted to extend objects, mixin works best)
  var Geneva = Class.create( Enumerable, {
    initialize: function ( selector ) {
      //  Set up
      this._elements = Object.isString( selector ) 
                      ?  $$(   selector   ) 
                      :  [ _$( selector ) ];
      
      // Try _$
      if ( this._elements.length < 1 )
        this._elements = [ _$( selector ) ];
      
      //!! TODO: add null checking, throw better errors
      
      // Store elements in array
      this._toArray();
    }
  });
  
  
  // Geneva's private parts
  Geneva.addMethods( {
    _toArray: function() {
      Array.prototype.push.apply(this, this._elements);
    },
    // usage: this.first() to substitute element
    _first: function() {
      return this._elements[0];
    },
    _each: function(iterator) {
      for (var i = 0, length = this.length; i < length; i++)
        iterator(this[i]);
    },
    _style : function ( value ) {
       if ( typeof value === 'object' ) 
        this.setStyle( value );
      else
        this.addClassName( value );
    }
  });

  Geneva.fn = {};
  Geneva.fn._copySourceMethods  = function () {
    
    _classobjects.each( function ( source ) {
      
      for ( var method in source ) {
        //  console.log(method);
        //  console.log( source[method] );


        //  Define Geneva compat copies of all methods. 
        //  with first _element argument support
        Geneva.prototype[ method ] = ( function ( method ) {
          
          //console.log( source[ method ].argumentNames() )  ;
          return function() { 

            var args = $A( arguments ), _first = false, _result, _elements = [];

            this._elements.each( function( element, i )  {

              // observe(  [element, event, callback] )
              _result = source[ method ]
                          .apply( null, args.length ? [ element ].concat(args) : [ element ] );

              if ( !Object.isElement( _result ) || Object.isUndefined( _result ) ) {
                //  console.log(_result);
                //  console.log('_first set true');
                _first = true; throw $break;
              }

              _result && ( _elements[i] = element );
            });

            if ( _first ) return _result;

            this._elements = _elements;
            return this;
          }

        //  pass the object's method as argument to the closure  
        })( method );
        //  End Geneva.prototype definition
      };
    });
  }

  Geneva.fn._copySourceMethods();
  
  //  Event support
  $w(
  //  Comp
  'composition compositionstart compositionend contextmenu ' +
  //  Drag
  'dragenter dragover dragexit dragdrop draggesture ' +
  //  Form
  'focus blur submit reset change select input ' +
  //  Keys
  'keydown keyup keypress ' +
  //  Doc
  'load beforeunload unload abort error ' +
  //  Mouse
  'mousedown mouseup click dblclick mouseover mouseout mousemove ' +
  //  Etc.
  'paint resize scroll overflow underflow overflowchanged text '
  )
  .each( function( type ) {
  
    Geneva.prototype[ type ] = ( function( type ) {
      //  Wrap event function in closure and return.
      
      return function( fn ) {
        
        // TEMPORARY STYLE CONTROL??
        //  just flashy... may need to omit.
        /*
          OPTION 1 : 
          if ( type === ( 'click' || 'dblclick' )  )
            this.setStyle( { cursor : 'hand', cursor : 'pointer' } );
            
            
          OPTION 2 :            
        */
          if ( arguments.length === 2 )
            this._style(arguments[1]);
        /*
        
        */
        // END -- TEMPORARY STYLE CONTROL
        
        if ( fn === undefined ) {
          var fn  = type() ;
          
          console.log(fn);
          console.log(type);
          console.log(this);
          return Element.fire(this._first(), type);
        }
        
        //return this.observe( type, fn ); //?
        return this.observe( type, function ( e ) {
          fn.call( this, e );
        });        
      }
    })( type );
  });
  
  //  $g as a convenience to Geneva
  this.$g = function(selector) {
    return new Geneva(selector);
  };

  //  $g can extend Geneva
  this.$g.addMethods = function( source ) {
    for ( var method in source )
      Geneva.prototype[ method ] = source[ method ];
  };
  
  //  $F() Adapter
  window.$F = function () {
    return _$( arguments[0] ).getValue();
  };
  
  // A copy of Prototype's $ as _$
  window._$ = function () {
    return new _$( arguments[0] );
  };

  //  $()  Adapter. RegEx patterns from jQuery
  window.$ = function( selector ) {
    
    if ( typeof selector === 'object' ) {
      if ( Object.isElement( selector ) && Object.isString( selector ) )
        return new Geneva( selector );
      
      return selector;
    }
    var _strExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/,
        _selExpr = /^.[^:#\[\.,]*$/,
        _selArr  = _strExpr.exec( selector );
    
    if ( _selArr && _selArr[3] ) {
      return new Geneva( _selArr[3] );
    } else {
      var _selArr   = _selExpr.exec( selector );
      
      if ( _selArr &&  _$( _selArr[0] ) ) 
        return new Geneva( _selArr[0] );
      
      return new Geneva( selector );
    }

    return new _$( selector );
  };

  //  Redefine Element.addMethods
  //  Any later defined additions will 
  //  be made compatible with Geneva
  Element.addMethods = ( function( source ) {
    var method = function() {
      source.apply( source, arguments );
      Geneva.fn._copySourceMethods();
    };
    return method;
  })( Element.addMethods );
  
    
  Element.addMethods();
  
//  Prototype $ as _$ within Geneva
})( $ ); 


//  Geneva compat serialize()
Form.Element.Methods.serialize = function() {
  el = _$( arguments[0] );
  if ( !el.disabled && el.name )
    return el.serialize();
  return '';
};

//  Interaction
$g.addMethods({
  hover   : function ( overFn, outFn ) {
    this.mouseover( overFn )
      .mouseout( outFn );
  }
});

$g.addMethods({

  // jquery desc: Get the combined text contents of all matched elements.
  text  : function ( v ) {
    ret = [];
    
    if ( v !== undefined ) {
      return this._elements.invoke('update',  (function ( v ) {
        return typeof v === 'function' ? v() : v ;
      })(v));
    } else  {
      this._elements.each( function (el) {
        ret.push(  el.innerHTML.trim()  );
      });
      return ret.join(', ');
    }
  }
});


//  Attributes : val, html
Element.addMethods({
  val  : function ( el,  v ) {
    el  = $( el );
    if ( v !== undefined )
      return el.update( v );
    else 
      return ( el.value ).trim();
    
    return el;
  },
  html  : function ( el,  v ) {
    el  = $( el );
    if ( v !== undefined )
      return el.update( v );
    else 
      return ( el.innerHTML ).clean().trim();
  }
});








//  Attributes : attr, removeAttr, [ add, has, remove, toggle ]Class, 
Element.addMethods({
  
  attr        : function  ( el, prop, val ) {
    el  = $( el );

    if ( typeof prop === 'string' && val === undefined )
      return el.readAttribute( prop );
  
    if ( typeof prop === 'object'  ) {
      for ( var key in prop  )
        el.writeAttribute( key, prop[ key ] );
     
      return el;
    }
    return el.writeAttribute( prop, ( typeof val === 'function' ? val() : val ) );
  }, 
  removeAttr  : function  ( el, prop ) {
    el  = $( el );
    
    return ( prop !== undefined 
              ? el.removeAttribute( prop )
              : el );
  },

  addClass    : function  ( el, val ) {
    el  = $( el );
    return el.addClassName ( val );
  },
  hasClass    : function  ( el, val ) {
    el  = $( el ); 
    return el.hasClassName ( val )
  },
  removeClass : function  ( el, val ) {
    el  = $( el );
    return el.removeClassName ( val );
  },
  toggleClass : function  ( el, val ) {
    el  = $( el );
    
    if ( el.hasClassName( val ) ) 
      return el.removeClassName ( val );
    else
      return el.addClassName ( val );
  }
});

Element.addMethods();